package org.beyondhc.lessons.observer;

import java.util.Observable;
import java.util.Observer;
import java.util.logging.Logger;

import junit.framework.TestCase;

import org.beyondhc.test.LogMsgCaptor;
import org.junit.Test;

/**
 * 
 * Shows how to (badly) use Java Observer-Observable.
 * 
 * @author Jaana Kulmala
 * 
 */
public class BadObserver extends TestCase {

    private class EmotionalMonkey extends Observable {

        public void setMood(final MonkeyMood mood) {
            setChanged();
            notifyObservers(mood);
        }

        @Override
        public String toString() {
            return "monkey";
        }
    }

    public class Koala extends Observable {

        public void setHungry(final boolean isHungry) {
            setChanged();
            notifyObservers(isHungry);
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

    public static enum MonkeyMood {
        HITTING_THINGS, HYPERACTIVE, OK
    }

    public class Tiger extends Observable {

        public void setHungry(final boolean isHungry) {
            setChanged();
            notifyObservers(isHungry);
        }

        @Override
        public String toString() {
            return "tiger";
        }
    }

    public class ZooKeeper implements Observer {

        @Override
        public void update(final Observable animal, final Object arg) {
            if (arg instanceof Boolean) {
                final boolean isHungry = (Boolean) arg;
                if (isHungry) {
                    LOGGER.info("Oh, the " + animal
                            + " is hungry. I'll go into the cage and "
                            + "give some eucalyptus to the little fella!");
                }

            }
        }
    }

    private static final transient Logger LOGGER = Logger
            .getLogger(BadObserver.class.getName());

    /**
     * This is the situation after little "maintenance". There is a new monkey,
     * that needs to be monitored more carefully than other animals.
     */
    @Test
    public void testEmotionalMonkeyGetsFood() { // NOPMD by kulmala on
                                                // 16.10.2011 12:47:
                                                // logMsgCaptor.verifyNothingLogged()
                                                // does the assertion.
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final EmotionalMonkey monkey = new EmotionalMonkey();
        final ZooKeeper zooKeeper = new ZooKeeper();

        monkey.addObserver(zooKeeper);
        monkey.setMood(MonkeyMood.HYPERACTIVE);
        // As this test goes through ok, the hyperactive monkey gets no food
        logMsgCaptor.verifyNothingLogged();
    }

    /**
     * This is what a newbie might code.
     */
    @Test
    public void testKoalaGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Koala koala = new Koala();
        final ZooKeeper zooKeeper = new ZooKeeper();

        koala.addObserver(zooKeeper);
        koala.setHungry(true);
        assertEquals("The zookeeper should get notified",
                "Oh, the koala is hungry. I'll go into the cage and "
                        + "give some eucalyptus to the little fella!",
                logMsgCaptor.getMsg());
    }

    /**
     * This is the situation after little "maintenance"
     */
    @Test
    public void testTiggerGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Tiger tigger = new Tiger();
        final ZooKeeper zooKeeper = new ZooKeeper();

        tigger.addObserver(zooKeeper);
        tigger.setHungry(true);
        // As this test goes through OK, we forgot to update the ZooKeeper
        assertEquals("Hmmm. Should the zookeeper go into the cage?",
                "Oh, the tiger is hungry. I'll go into the cage and "
                        + "give some eucalyptus to the little fella!",
                logMsgCaptor.getMsg());
    };
}
